#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/8/5 14:31
# @Author : luhongxuan
# @Site :
# @File : auth.py
# @Software: PyCharm

import logging.config
import os
import time
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler


class SafeTimedRotatingFileHandler(TimedRotatingFileHandler):
    """
    Handler for logging to a file, rotating the log file at certain timed
    intervals.

    If backupCount is > 0, when rollover is done, no more than backupCount
    files are kept - the oldest ones are deleted.
    """

    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False,
                 atTime=None):
        TimedRotatingFileHandler.__init__(self, filename, when, interval, backupCount, encoding, delay, utc, atTime)

    def doRollover(self):
        """
        do a rollover; in this case, a date/time stamp is appended to the filename
        when the rollover happens.  However, you want the file to be named for the
        start of the interval, not the current time.  If there is a backup count,
        then we have to get a list of matching filenames, sort them and remove
        the one with the oldest suffix.
        """
        if self.stream:
            self.stream.close()
            self.stream = None
        # get the time that this sequence started at and make it a TimeTuple
        currentTime = int(time.time())
        dstNow = time.localtime(currentTime)[-1]
        t = self.rolloverAt - self.interval
        if self.utc:
            timeTuple = time.gmtime(t)
        else:
            timeTuple = time.localtime(t)
            dstThen = timeTuple[-1]
            if dstNow != dstThen:
                if dstNow:
                    addend = 3600
                else:
                    addend = -3600
                timeTuple = time.localtime(t + addend)
        dfn = self.rotation_filename(self.baseFilename + "." +
                                     time.strftime(self.suffix, timeTuple))
        # if os.path.exists(dfn):
        #     os.remove(dfn)
        self.rotate(self.baseFilename, dfn)
        if self.backupCount > 0:
            for s in self.getFilesToDelete():
                os.remove(s)
        if not self.delay:
            self.stream = self._open()
        newRolloverAt = self.computeRollover(currentTime)
        while newRolloverAt <= currentTime:
            newRolloverAt = newRolloverAt + self.interval
        # If DST changes and midnight or weekly rollover, adjust for this.
        if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
            dstAtRollover = time.localtime(newRolloverAt)[-1]
            if dstNow != dstAtRollover:
                if not dstNow:  # DST kicks in before next rollover, so we need to deduct an hour
                    addend = -3600
                else:  # DST bows out before next rollover, so we need to add an hour
                    addend = 3600
                newRolloverAt += addend
        self.rolloverAt = newRolloverAt

    def rotate(self, source, dest):
        """
        When rotating, rotate the current log.

        The default implementation calls the 'rotator' attribute of the
        handler, if it's callable, passing the source and dest arguments to
        it. If the attribute isn't callable (the default is None), the source
        is simply renamed to the destination.

        :param source: The source filename. This is normally the base
                       filename, e.g. 'test.log'
        :param dest:   The destination filename. This is normally
                       what the source is rotated to, e.g. 'test.log.1'.
        """
        if not callable(self.rotator):
            # Issue 18940: A file may not have been created if delay is True.
            if os.path.exists(source) and not os.path.exists(dest):
                os.rename(source, dest)
        else:
            self.rotator(source, dest)


def logger_defaults(log_path):
    """
    标准日志方法，包含所有类型的日志，并将日志输出到控制台以及日志文件。
    :return:
    """
    zet_core_path = log_path if log_path else os.path.dirname(os.path.abspath(__file__))  # 当前文件所在的文件夹目录

    filename = 'default.log'
    log_path = os.path.join(zet_core_path, 'logs', 'all')
    if not os.path.exists(log_path):
        os.makedirs(log_path)
    log_file = os.path.join(log_path, filename)  # 项目的log文件，不要修改本行
    handler_default = SafeTimedRotatingFileHandler(log_file, when='midnight', interval=1, backupCount=365,
                                                   encoding='utf-8')
    handler_console = logging.StreamHandler()  # 日志信息输出到控制台

    # 定义输出格式
    fmt = ' %(levelname)s : %(asctime)s - %(filename)s:%(lineno)s - %(funcName)s - %(message)s'
    formatter = logging.Formatter(fmt)  # 实例化formatter
    handler_default.setFormatter(formatter)  # 为handler添加formatter
    handler_console.setFormatter(formatter)

    logger = logging.getLogger('tst')  # 获取名为tst的logger
    logger.addHandler(handler_default)  # 为logger添加handler
    logger.addHandler(handler_console)

    logger.setLevel(logging.DEBUG)
    return logger


def logger_errors(log_path):
    """
    错误日志方法，只记录error及其以上的日志信息，并将日志输出到日志文件
    :return:
    """
    zet_core_path = log_path if log_path else os.path.dirname(os.path.abspath(__file__))  # 当前文件所在的文件夹目录

    filename = 'error.log'
    log_path = os.path.join(zet_core_path, 'logs', 'errors')
    if not os.path.exists(log_path):
        os.makedirs(log_path)
    log_file = os.path.join(log_path, filename)  # 项目的log文件，不要修改本行

    handler_default = SafeTimedRotatingFileHandler(log_file, when='midnight', interval=1, backupCount=365,
                                                   encoding='utf-8')
    # 定义输出格式
    fmt = ' %(levelname)s : %(asctime)s - %(filename)s:%(lineno)s - %(funcName)s - %(message)s'
    formatter = logging.Formatter(fmt)  # 实例化formatter
    handler_default.setFormatter(formatter)  # 为handler添加formatter

    logger = logging.getLogger('error')  # 获取名为error的logger
    logger.addHandler(handler_default)  # 为logger添加handler

    logger.setLevel(logging.ERROR)
    return logger


def logger_custom(filename, log_path, dirname='custom', logger_level=logging.DEBUG):
    """
    自定义日志逻辑方法
    :param filename:
    :param dirname:
    :param logger_level:
    :return:
    """
    zet_core_path = log_path if log_path else os.path.dirname(os.path.abspath(__file__))  # 当前文件所在的文件夹目录
    log_path = os.path.join(zet_core_path, 'logs', dirname)
    log_file = os.path.join(log_path, filename)  # 项目的log文件，不要修改本行
    log_dir = os.path.dirname(log_file)

    if not os.path.exists(log_dir):
        os.makedirs(log_dir)

    handler_default = logging.handlers.RotatingFileHandler(log_file, maxBytes=1024 * 1024 * 10,
                                                           backupCount=2)  # 日志信息输出到文件

    # 定义输出格式
    fmt = ' %(levelname)s : %(asctime)s - %(filename)s:%(lineno)s - %(funcName)s - %(message)s'
    formatter = logging.Formatter(fmt)  # 实例化formatter
    handler_default.setFormatter(formatter)  # 为handler添加formatter

    file_name_without_suffix = os.path.basename(log_file).split('.')[0]
    logger = logging.getLogger(file_name_without_suffix)
    logger.addHandler(handler_default)  # 为logger添加handler

    logger.setLevel(logger_level)
    return logger


logger_default = logger_defaults()
logger_error = logger_errors()
